package com.mathlearning.auth.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mathlearning.auth.dto.message.SendMessageRequest;
import com.mathlearning.auth.dto.message.MessageResponse;
import com.mathlearning.auth.dto.websocket.WebSocketMessage;
import com.mathlearning.auth.entity.User;
import com.mathlearning.auth.repository.UserRepository;
import com.mathlearning.auth.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket 消息处理器
 */
@Component
public class MessageWebSocketHandler extends TextWebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(MessageWebSocketHandler.class);

    // 存储所有在线用户的 WebSocket 连接
    private static final ConcurrentHashMap<Long, WebSocketSession> ONLINE_USERS = new ConcurrentHashMap<>();

    @Autowired
    private MessageService messageService;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 连接建立成功
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Long userId = (Long) session.getAttributes().get("userId");
        ONLINE_USERS.put(userId, session);

        logger.info("用户 {} 建立 WebSocket 连接，当前在线用户数: {}", userId, ONLINE_USERS.size());

        // 发送连接成功消息
        Map<String, Object> data = new HashMap<>();
        data.put("userId", userId);
        data.put("message", "连接成功");

        WebSocketMessage response = new WebSocketMessage("CONNECTED", data);
        sendMessage(session, response);
    }

    /**
     * 处理客户端发送的文本消息
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        Long userId = (Long) session.getAttributes().get("userId");
        String payload = message.getPayload();

        logger.info("收到用户 {} 的消息: {}", userId, payload);

        try {
            Map<String, Object> msg = objectMapper.readValue(payload, Map.class);
            String type = (String) msg.get("type");

            switch (type) {
                case "SEND_MESSAGE":
                    handleSendMessage(userId, msg, session);
                    break;
                case "PING":
                    handlePing(session);
                    break;
                default:
                    logger.warn("未知的消息类型: {}", type);
                    sendError(session, "UNKNOWN_TYPE", "未知的消息类型");
                    break;
            }
        } catch (Exception e) {
            logger.error("处理消息失败: {}", e.getMessage(), e);
            sendError(session, "PARSE_ERROR", "消息格式错误");
        }
    }

    /**
     * 处理发送私信
     */
    private void handleSendMessage(Long senderId, Map<String, Object> msg, WebSocketSession senderSession) throws Exception {
        try {
            Map<String, Object> data = (Map<String, Object>) msg.get("data");
            Long receiverId = ((Number) data.get("receiverId")).longValue();
            String content = (String) data.get("content");

            logger.info("用户 {} 向用户 {} 发送消息: {}", senderId, receiverId, content);

            // 创建发送消息请求对象
            SendMessageRequest request = new SendMessageRequest();
            request.setReceiverId(receiverId);
            request.setContent(content);

            // 保存消息到数据库
            MessageResponse messageResponse = messageService.sendMessage(senderId, request);

            // 查询发送者信息
            User sender = userRepository.findById(senderId).orElse(null);
            String senderName = sender != null ? sender.getNickname() : "未知用户";
            String senderAvatar = sender != null ? sender.getAvatar() : null;

            // 构建消息响应数据
            Map<String, Object> messageData = new HashMap<>();
            messageData.put("id", messageResponse.getId());
            messageData.put("senderId", senderId);
            messageData.put("senderName", senderName);
            messageData.put("senderAvatar", senderAvatar);
            messageData.put("receiverId", receiverId);
            messageData.put("content", content);
            messageData.put("createTime", messageResponse.getCreateTime());
            messageData.put("isRead", false);

            // 发送确认给发送者
            WebSocketMessage sentResponse = new WebSocketMessage("MESSAGE_SENT", messageData);
            sendMessage(senderSession, sentResponse);

            // 推送给接收者（如果在线）
            WebSocketSession receiverSession = ONLINE_USERS.get(receiverId);
            if (receiverSession != null && receiverSession.isOpen()) {
                WebSocketMessage newMsgResponse = new WebSocketMessage("NEW_MESSAGE", messageData);
                sendMessage(receiverSession, newMsgResponse);
                logger.info("消息已推送给在线用户 {}", receiverId);
            } else {
                logger.info("用户 {} 不在线，消息将在下次登录时获取", receiverId);
            }

        } catch (Exception e) {
            logger.error("发送消息失败: {}", e.getMessage(), e);
            sendError(senderSession, "SEND_FAILED", "消息发送失败: " + e.getMessage());
        }
    }

    /**
     * 处理心跳包
     */
    private void handlePing(WebSocketSession session) throws Exception {
        WebSocketMessage response = new WebSocketMessage("PONG", null);
        sendMessage(session, response);
    }

    /**
     * 连接关闭
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        Long userId = (Long) session.getAttributes().get("userId");
        ONLINE_USERS.remove(userId);
        logger.info("用户 {} 断开 WebSocket 连接，当前在线用户数: {}", userId, ONLINE_USERS.size());
    }

    /**
     * 传输错误处理
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        Long userId = (Long) session.getAttributes().get("userId");
        logger.error("用户 {} WebSocket 发生错误: {}", userId, exception.getMessage(), exception);
        ONLINE_USERS.remove(userId);
    }

    /**
     * 发送 WebSocket 消息
     */
    private void sendMessage(WebSocketSession session, WebSocketMessage message) throws Exception {
        if (session != null && session.isOpen()) {
            String jsonMessage = objectMapper.writeValueAsString(message);
            session.sendMessage(new TextMessage(jsonMessage));
        }
    }

    /**
     * 发送错误消息
     */
    private void sendError(WebSocketSession session, String code, String message) throws Exception {
        Map<String, Object> errorData = new HashMap<>();
        errorData.put("code", code);
        errorData.put("message", message);
        WebSocketMessage response = new WebSocketMessage("ERROR", errorData);
        sendMessage(session, response);
    }


    /**
     * 工具方法：向指定用户发送消息
     */
    public static void sendMessageToUser(Long userId, WebSocketMessage message, ObjectMapper objectMapper) {
        try {
            WebSocketSession session = ONLINE_USERS.get(userId);
            if (session != null && session.isOpen()) {
                String jsonMessage = objectMapper.writeValueAsString(message);
                session.sendMessage(new TextMessage(jsonMessage));
            }
        } catch (Exception e) {
            logger.error("向用户 {} 发送消息失败: {}", userId, e.getMessage());
        }
    }

    /**
     * 获取在线用户数
     */
    public static int getOnlineUserCount() {
        return ONLINE_USERS.size();
    }

    /**
     * 检查用户是否在线
     */
    public static boolean isUserOnline(Long userId) {
        return ONLINE_USERS.containsKey(userId) && ONLINE_USERS.get(userId).isOpen();
    }
}



